package io.xxx.omni.osc.sync

import com.alibaba.fastjson.JSONObject
import io.xxx.omni.osc.common.dateTimeFormatter
import io.xxx.omni.osc.common.toJSONObject
import io.xxx.omni.osc.common.toLocalDateTime
import io.xxx.omni.osc.domain.Document
import io.xxx.omni.osc.domain.DocumentType
import io.xxx.omni.osc.domain.PlatformIdentity
import io.xxx.omni.osc.domain.Store
import io.xxx.omni.osc.sdk.JdClient
import org.springframework.stereotype.Component
import java.time.LocalDateTime

/**
 * 京东
 */
// https://open.jd.com/home/home#/doc/common
@Suppress("UnstableApiUsage")
abstract class JdPorter : GenericPageDocumentPorter(), PlatformIdentity.JingDong {

    protected abstract val method: String

    override val permitsPerMinutes = 300

    override fun getResponse(context: JobContext, pageNo: Int, hasTotal: Boolean): JSONObject {
        val (store, startTime, endTime, parameter) = context
        val request = buildRequest(startTime, endTime, parameter, pageNo)
        val client = applicationContext.getBean(JdClient::class.java)
        val response = client.execute(store, method, request)
        if (response.getString("code") != null) {
            throwException(context, request, response)
        }
        return response
    }

    override fun getCount(context: JobContext, response: JSONObject): Int =
        getResult(context, response).getInteger("orderTotal")

    protected abstract fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Int,
    ): Map<String, Any>

    protected abstract fun getResult(context: JobContext, response: JSONObject): JSONObject
}

// 订单
@Component
class JdTradePorter : JdPorter() {

    override val documentType = DocumentType.TRADE

    override val method = "jingdong.pop.order.search"

    override fun getParameters(store: Store) = listOf(0) to false

    override fun buildDocuments(context: JobContext, response: JSONObject): List<Document> {
        val result = getResult(context, response)
        return result
            .getJSONArray("orderInfoList")
            .map {
                val value = it.toJSONObject()
                val sn = value.getString("orderId")
                val status = value.getString("status")
                val modified = value.getString("modified").toLocalDateTime()
                Document(sn, status, modified, value)
            }
    }

    override fun getResult(context: JobContext, response: JSONObject): JSONObject {
        if (response.containsKey("error_response")) {
            throwException(context, method, response)
        }
        val result = response
            .getJSONObject("jingdong_pop_order_search_responce")
            .getJSONObject("searchorderinfo_result")
        val apiResult = result.getJSONObject("apiResult")
        if (!apiResult.getBoolean("success")) {
            throwException(context, method, response)
        }
        return result
    }

    override fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Int
    ): Map<String, Any> {
        return mapOf(
            "sortType" to 1,
            "dateType" to 0,
            "start_date" to startTime.format(dateTimeFormatter),
            "end_date" to endTime.format(dateTimeFormatter),
            "page" to pageNo,
            "page_size" to pageSize,
            "optional_fields" to optionalFields.joinToString(","),
            "order_state" to orderStates.joinToString(","),
        )
    }

    companion object {
        private val optionalFields = listOf(
            "orderSellerPrice", "orderType", "logisticsId", "orderSign", "orderId",
            "paymentConfirmTime", "orderStateRemark", "orderState", "payType", "itemInfoList",
            "pin", "waybill", "customc", "modified", "salesPin",
            "freightPrice", "tuiHuoWuYou", "balanceUsed", "serviceFee", "directParentOrderId",
            "originalConsigneeInfo", "orderTotalPrice", "invoiceCode", "mdbStoreId", "idSopShipmenttype",
            "sellerDiscount", "customcModel", "venderRemark", "couponDetailList", "menDianId",
            "venderId", "orderRemark", "orderMarkDesc", "scDT", "parentOrderId",
            "orderEndTime", "taxFee", "vatInfo", "open_id_buyer", "open_id_seller",
            "invoiceInfo", "orderSource", "orderExt", "deliveryType", "pauseBizInfo",
            "storeId", "orderPayment", "consigneeInfo", "returnOrder", "invoiceEasyInfo",
            "storeOrder", "realPin", "orderStartTime",
        )

        private val orderStates = listOf(
            "WAIT_SELLER_STOCK_OUT", "WAIT_GOODS_RECEIVE_CONFIRM", "WAIT_SELLER_DELIVERY", "PAUSE", "FINISHED_L",
            "TRADE_CANCELED", "LOCKED", "POP_ORDER_PAUSE"
        )
    }
}

// 退单
@Component
class JdRefundPorter : JdPorter() {

    override val documentType = DocumentType.REFUND

    override val method = "jingdong.pop.afs.soa.refundapply.queryPageList"

    override val pageSize = 50

    override fun buildDocuments(context: JobContext, response: JSONObject): List<Document> {
        val result = getResult(context, response)
        return result.getJSONArray("result").map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            val sn = value.getString("id")
            val rsn = value.getString("orderId")
            val status = value.getString("status")
            val modified = (value.getString("checkTime")
                ?: value.getString("applyTime")).toLocalDateTime()
            Document(sn, rsn, status, modified, value)
        }
    }

    override fun getResult(context: JobContext, response: JSONObject): JSONObject {
        val result = response.getJSONObject("jingdong_pop_afs_soa_refundapply_queryPageList_responce")
            .getJSONObject("queryResult")
        if (!result.getBoolean("success")) {
            throwException(context, method, response)
        }
        return result
    }

    override fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Int
    ): Map<String, Any> {
        return mapOf(
            "applyTimeStart" to startTime.format(dateTimeFormatter),
            "applyTimeEnd" to endTime.format(dateTimeFormatter),
            "pageIndex" to pageNo,
            "pageSize" to pageSize,
        )
    }
}